package redis

import (
	"time"

	"github.com/go-redis/redis"
)

var (
	clients map[string]map[string]*redis.Client
)

const (
	DefaultMaxRetries   = 3
	DefaultDialTimetout = 100 * time.Millisecond
	DefaultReadTimeout  = 100 * time.Millisecond
	DefaultWriteTimeout = 100 * time.Millisecond
	DefaultPoolSize     = 0
	DefaultMinIdleConns = 0

	Master = "master"
	Slave  = "slave"
	Nil    = redis.Nil
)

type Conf struct {
	Addr         string
	SlaveAddr    string `mapstructure:"slave_addr"`
	MaxRetries   int
	DialTimeout  time.Duration
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	// PoolSize applies per cluster node and not for the whole cluster.
	PoolSize     int
	MinIdleConns int
}

func DefaultConf() Conf {
	return Conf{
		MaxRetries:   DefaultMaxRetries,
		DialTimeout:  DefaultDialTimetout,
		ReadTimeout:  DefaultReadTimeout,
		WriteTimeout: DefaultWriteTimeout,
		PoolSize:     DefaultPoolSize,
		MinIdleConns: DefaultMinIdleConns,
	}
}

func New(confs map[string]Conf) error {
	clients = make(map[string]map[string]*redis.Client)
	for k, v := range confs {
		clients[k] = make(map[string]*redis.Client, 2)
		clients[k][Master] = redis.NewClient(&redis.Options{
			Addr:         v.Addr,
			MaxRetries:   v.MaxRetries,
			DialTimeout:  v.DialTimeout,
			ReadTimeout:  v.ReadTimeout,
			WriteTimeout: v.WriteTimeout,
			PoolSize:     v.PoolSize,
			MinIdleConns: v.MinIdleConns,
		})
		if v.SlaveAddr != "" {
			clients[k][Slave] = redis.NewClient(&redis.Options{
				Addr:         v.SlaveAddr,
				MaxRetries:   v.MaxRetries,
				DialTimeout:  v.DialTimeout,
				ReadTimeout:  v.ReadTimeout,
				WriteTimeout: v.WriteTimeout,
				PoolSize:     v.PoolSize,
				MinIdleConns: v.MinIdleConns,
			})
		}
	}
	return nil
}

func Get(name string, master ...bool) (*redis.Client, bool) {
	conn, ok := clients[name]
	if !ok {
		return nil, false
	}
	key := Master
	if len(master) > 0 && master[0] != true {
		key = Slave
	}
	client, ok := conn[key]
	return client, ok
}
